# -*- coding: utf_8 -*-
# @Time : 2021/8/9 0009 14:46
# @Author : lyw
# @Remark : 门禁公共接口
import os
import logging
import threading
import time
from os.path import exists
from db.common.IOTManager.Janitor.public_interface import PublicInterfaceDB, DataInsertDB
from mxsoftpy import Server
from mxsoftpy.exception import DBError

from model.common.IOTManager.Janitor.public_interface import RecDoorModel, RecordModel, PersonnelModel
from server.common.IOTManager.Janitor.door import GetDoorInfoServer
from server.common.IOTManager.Janitor.personnel import PersonnelServer
from utils.classes.custom_exception import VerifyError

from server.common.IOTManager.Janitor.record import RecordServer
from utils.public.export_execl import ExportExecl

from utils.public.mini_cache import MiniCache


class DataOriginConfigServer(Server):
    """获取数据源数据配置"""
    __db__ = PublicInterfaceDB

    def model_data_info(self, host, model_id):
        """
        获取数据源配置
        @param host:
        @param model_id:
        @return:
        """
        public_interface_db = self.__db__()
        data_origin = public_interface_db.get_data_origin(host)
        door = []
        origin_model = {}
        if data_origin:
            origin_model = public_interface_db.get_origin_model(data_origin["model_id"])
            door = public_interface_db.get_door(origin_id=data_origin["id"])
        else:
            if model_id:
                origin_model = public_interface_db.get_origin_model(model_id)
        return {"data_origin": data_origin, "origin_model": origin_model, "door": door}


class InsertDoorServer(Server):
    """新增门禁"""
    __db__ = DataInsertDB
    __model__ = RecDoorModel

    def insert_door(self, **kwargs):
        """
        插入未采集的门禁
        @param kwargs:
        @return:
        """
        sub_key = "rec_door"
        print(kwargs)
        door_data = self.model(**kwargs).dict()
        if door_data["model_id"] not in self.db.query_model():
            raise VerifyError("model_id参数不正确...")
        # if door_data["origin_id"] not in self.db.query_origin():
        #     raise VerifyError("origin_id参数不正确...")

        door_id = self.db.query_data(sub_key=sub_key, host=door_data["host"],
                                     device_id=door_data["device_id"], is_del=0)[0]
        if door_id:
            self.db.update(sub_key=sub_key, double_key=door_id, insert_dict=door_data)
        elif door_data["is_del"]:
            return door_id
        else:
            door_id = self.db.create(sub_key=sub_key, insert_dict=door_data)
        return door_id


class InsertRecordServer(Server):
    """新增出入记录"""
    __db__ = DataInsertDB
    __model__ = RecordModel

    def insert_record(self, **kwargs):
        sub_key = "record"
        record_data = self.model(**kwargs).dict()

        record_door = self.db.query_door()

        record_pers = self.db.query_personnel()

        if record_data["door_id"] not in record_door:
            raise VerifyError("door_id不正确... ")
        if record_data["pers_id"] not in record_pers:
            raise VerifyError("pers_id不正确... ")

        record_id, record = self.db.query_data(pers_id=record_data["pers_id"], door_id=record_data["door_id"],
                                               create_time=record_data["create_time"])
        # if record_data["model_id"] not in self.db.query_model():
        #     raise VerifyError("model_id不正确... ")
        if record_id:
            self.db.update(sub_key=sub_key, double_key=record_id, insert_dict=record_data)
        else:
            record_id = self.db.create(sub_key=sub_key, insert_dict=record_data)

        return record_id


class InsertPersonnelServer(Server):
    """新增人员"""
    __db__ = DataInsertDB
    __model__ = PersonnelModel

    def insert_personnel(self, **kwargs):
        sub_key = "personnel"
        personnel_data = self.model(**kwargs).dict()
        query_door = self.db.query_door()
        if personnel_data["door_id"] not in query_door:
            raise VerifyError("door_id不正确... ")
        return self.file_lock(sub_key, personnel_data)

    def file_lock(self, sub_key, personnel_data):
        """
        文件锁 防止人员混乱 进行堵塞线线程使用
        @param sub_key:
        @param personnel_data:
        @param personnel_dict:
        @return:
        """
        import platform
        if platform.system() == "Windows":
            from utils.public import win_fcntl_lock as fcntl

        else:
            import fcntl
        with open("./janitor_lock.txt", "w") as file:
            fcntl.flock(file, fcntl.LOCK_EX)

            personnel_dict = self.db.query_personnel_data(sub_key="personnel", is_del=0)
            cache_key = "_".join((personnel_data["serial_num"], personnel_data["door_id"]))
            personnel_id = personnel_dict.get()
            if personnel_id is not None:
                # personnel_data.pop("create_time")
                try:
                    self.db.update(sub_key=sub_key, double_key=personnel_id, insert_dict=personnel_data)
                except DBError:
                    personnel_id = self.db.create(sub_key=sub_key, insert_dict=personnel_data)

                    personnel_dict[cache_key] = personnel_id  # 添加到缓存

                if personnel_data["is_del"]:  # 判断是否删除
                    del personnel_dict[cache_key]  # 删除缓存
                    return personnel_id
            else:
                personnel_id = self.db.create(sub_key=sub_key, insert_dict=personnel_data)
                personnel_dict[cache_key] = personnel_id
            fcntl.flock(file, fcntl.LOCK_UN)

        return personnel_id


class ExportExeclServer(Server):
    # 导出设置
    get_personnel = PersonnelServer().get_personnel
    get_record = RecordServer().get_record
    get_door_info = GetDoorInfoServer().get_door_info

    def export_execl(self, **kwargs):
        export_type = {"1": "get_personnel", "2": "get_record", "3": "get_door_info"}
        if hasattr(self, export_type.get(kwargs.get("type"), "")):
            export_fun = getattr(self, export_type.get(kwargs.get("type"), ""))
        else:
            raise VerifyError("参数错误...")
        export_model = self.export_definition(kwargs.get("type"))
        file_path = self.file_processing(export_model["header"])
        export_model["data"] = list()
        if kwargs.get("type") == "3":
            kwargs["origin_id"] = "1"
            kwargs["pageindex"] = 1
            kwargs["pagesize"] = 1
        for data in export_fun(**kwargs)["data"]:
            export_model["data"].append(data)
            # return data
        try:
            ExportExecl().data_process(export_model)(os.path.join(file_path[0], file_path[1]))
        except AssertionError:
            raise VerifyError("查询数据不存在")

        return file_path[2]

    @staticmethod
    def export_definition(type_id: str) -> dict:
        data_dict = {"1": {"header": "人员",
                           "headline": {"id": "序号", "name": "人员姓名", "badge_number": "人员编号",
                                        "fingerprint": "通行标识", "update_time": "记录时间", "state": "标识状态", }},
                     "2": {"header": "出入记录",
                           "headline": {"id": "序号", "personnel": "人员姓名", "fingerprint": "通行标识", "motion": "出/入",
                                        "door_name": "门禁名称", "create_time": "采集时间", "desc": "备注"}},
                     "3": {"header": "门禁",
                           "headline": {"order_number": "序号", "label": "门禁名称", "auth_method": "认证方式",
                                        "origin_id": "数据源名称", }},
                     }
        return data_dict[type_id]

    @staticmethod
    def file_processing(file_name: str) -> tuple:
        file_name = f"{file_name}{time.strftime('%H%M%S', time.localtime())}.xlsx"
        # file_path = os.getcwd()
        file_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
        file_path = os.path.dirname(os.path.dirname(os.path.dirname(file_path)))
        addr = os.path.join("hdoc", "janitor")
        # 创建文件夹
        if not exists(os.path.join(file_path, addr)):
            os.mkdir(os.path.join(file_path, addr))
        # 清理文件
        dir_list = os.listdir(os.path.join(file_path, addr))
        for f in dir_list:
            file = os.path.join(file_path, addr, f)
            if os.path.isfile(file):
                os.remove(file)
        return file_path, os.path.join(addr, file_name), file_name


class RecordAndPersonnelServer(InsertPersonnelServer):

    def process(self, param):
        """人员记录添加"""

        records = []
        for pers in param:
            logging.info("人员推送")
            logging.info("线程的名字:%s" % threading.currentThread().name)
            logging.info("线程的id:%d" % threading.currentThread().ident)
            pers_id = self.insert_personnel(**pers)
            records.append(pers_id)

        return ",".join(records)

    def threading_process(self, **kwargs):
        param = kwargs["data"]
        logging.info("门禁推送的数据长是%d" % len(param))
        t1 = threading.Thread(target=self.process, args=(param,))
        t1.start()
        return "ok"


class GetPersonnelServer(Server):
    __db__ = DataInsertDB

    # def get_personnel(self, serial_num, door_id):
    def get_personnel(self, **kwargs):
        if kwargs.get("serial_num"):
            return self.db.query_data(sub_key="personnel", **kwargs)
        else:
            return self.db.query_user_list(**kwargs)


class BatchNewRecordServer(InsertRecordServer):

    def batch_new_record(self, param):
        """批量新记录"""

        for record in param:
            logging.info("记录推送")
            logging.info("线程的名字:%s" % threading.currentThread().name)
            logging.info("线程的id:%d" % threading.currentThread().ident)
            self.insert_record(**record)
        return 0

    def threading_process(self, **kwargs):
        param = kwargs["data"]

        logging.info("门禁记录推送的数据长是%d" % len(param))
        t1 = threading.Thread(target=self.batch_new_record, args=(param,))

        t1.start()
        return "ok"
